#include "board.h"
#include "link.h"
#include "tss_writer.h"
#include "components\adc_keyboard\adc_keyboard.h"
#include "components\battery_manager\battery_manager.h"
#include "components\lcd_drivers\lcd.h"
#include "polsys.h"



// 外部函数声明




static u16 mVoltageVBus;              // VBUS上的电压 mV
static u16 mVoltageVBusLast;
static bool mIsPlugIn = false;
static u8 mPlugCheckStep = 1;       // 0 停止检测，1开始检测，其它表示等待计时

static vu16 mBatVoltage = 0xffff;        // 电池电压 mV
static vu16 mLight = 0;                    // 光线强度值（ADC采样值，数值越小光线越强）
static vu16 mAdcKbValue = 0;
static vu16 mTestDnVoltage = 0;         // TEST_DN 脚的电压 mV
static u8 mAdcChMask;   // 要转换的ADC通道掩码
static vu8 mAdcConvertedCh = 0;
static volatile bool mAdcMissData = false;  // 本次转换有数据因无效被丢弃
static volatile bool mAdcDone = false;      // true:本次转换完毕,false:正在转换或者还未启动过转换

static u32 mRand;

static bool mNeedSleep = false;

static u32 BootTime = 0;    // 本次已开机时间，单位0.1s
static u16 mResetTime = 0;   // 复位操作计时，时间到后复位
static polsys_task_t mTimer;


static void DmaInit();
static void GpioInit();
static void SPI0_Init();

// Uart0 用于Dp通信
static void Uart0_Init();
static void Uart0_Event(uart_Evt_t *e);
// Uart1 用于VBus通信
static void Uart1_Init(u32 baud);
static void Uart1_Event(uart_Evt_t *e);

static void Board_AdcStartScan(u8 ch_mask);
static void Adc_Event(AdcEvt_t* e);

static void Board_EnterSleep();

static void BoardTimer();


void Gpio_EventHdl(GpioPin_t pin,gpio_polarity_e type);


IN_LINE void Board_Init()
{
    DmaInit();
    GpioInit();
    SPI0_Init();
    Uart0_Init();
    
    // 刚上电时等待一次ADC采集结束
    Board_VExtOn();
    Board_AdcStartScan(ADC_CH_VBAT_MASK);       // ADC开始运行一次
    while(mBatVoltage == 0xffff)    // 等待ADC转换结束
    {
        if(mAdcDone)    // 转换完毕但是未获取电压值，说明有数据丢失，重新转换
        {
            Board_AdcStartScan(ADC_CH_VBAT_MASK);       // ADC开始运行一次
        }
    }
    if(mBatVoltage < 3350)  // 电量很低
    {
        // while (Keyboard_GetLastStatus() != KEY_STATUS_RELEASE); 
        Board_EnterSleep();
    }

    Polsys_TaskInit(&mTimer, BoardTimer, 30/POLSYS_TICK_CYCLE);

    #ifndef TSS_DEBUG
    Wdt_Init();
    #endif
}

const gpio_init_param_t GpioIdleList[] = GPIO_IDLE_LIST;
void Board_Idle()
{
    for(u8 i = 0; i < sizeof(GpioIdleList) / sizeof(gpio_init_param_t); i++)
        Gpio_PinInit(&GpioIdleList[i]);

    // SPI_MISO_PIN_GPIO_IN_HZ;
    // SPI_MOSI_PIN_GPIO_IN_HZ;
    // SPI_SCK_PIN_GPIO_IN_HZ;
    // Board_SetLcdRsLevel(0); // 1
    // VBUS_TX_PIN_GPIO_OUT_L;
    // VBUS_RX_PIN_AIN;
    // HalGpioFmuxConfig(TEST_DP_PIN, FMUX_UART0_RX);
    // TEST_DN_FLOAT
    // AIN_TCHRG_FLOAT_AIN
    // AIN_LIGHT_FLOAT_AIN
    // AIN_VBAT_FLOAT_AIN
    // DCIN下拉100K输入
    // FLASH_CS = 1
    // LCD_CS = 1 ？
    // Board_SetVBusHzLevel(0);//0?
    // Board_VExtOff();
}

static void Dma_Event(DMA_CH_t ch)
{
#if (_SPI_USE_ASNYC && (_SPI_EN_DMA_TX || _SPI_EN_DMA_RX))
    Spi_EvDmaTransCompleted();
#endif
}

static void DmaInit()
{
    HAL_DMA_t ch_cfg;
    HalDMAInit();
    ch_cfg.dma_channel = DMA_CH_0;
    ch_cfg.evt_handler = Dma_Event;
    HalDMAInitChannel(ch_cfg);  // 实际上就是设置回调的函数
}

static void Board_EnterSleep()
{
    pwroff_cfg_t cfg[2];

    cfg[0].on_time = 0;
    cfg[0].pin = DCIN_PIN;
    cfg[0].type = POL_RISING;

    cfg[1].on_time = 0;
    cfg[1].pin = AIN_KB_PIN;
    cfg[1].type = POL_RISING;

    // 耗电降到最低的代码
    Board_Idle();

    HalGpioAnalogConfig(AIN_KB_PIN, Bit_DISABLE);
    HalGpioWkupConfig(AIN_KB_PIN, POL_RISING);  
    HalGpioRegister(AIN_KB_PIN, Gpio_EventHdl, Gpio_EventHdl);

    HalGpioWkupConfig(DCIN_PIN, POL_RISING);
    HalGpioRegister(DCIN_PIN, Gpio_EventHdl, Gpio_EventHdl);

    // Mcu_EnterLowPower();    // 让MCU进入低功耗蓝牙状态
    hal_pwrmgr_poweroff(&cfg[0],2);    // 唤醒后将直接复位
}

void Board_Sleep()
{
    // 先关闭显示
    Board_SetLcdBrightness(0);
    Lcd_DispOff();
    // 再标记需要休眠（关机）
    mNeedSleep = true;  // 需要等待按键全部松手后再休眠
}

void Gpio_EventHdl(GpioPin_t pin,gpio_polarity_e type)
{
    // Mcu_ExitLowPower();     // 让MCU退出低功耗蓝牙
}

void Board_SetLcdBrightness(u8 br)
{
    if(br == 0)
    {
        Board_SetLcdBrLevel(0);
    }
    else
    {
        Board_SetLcdBrLevel(1);
    }
}

IN_LINE u32 Board_GetRand()
{
    return mRand;
}


IN_LINE u16 Board_GetVBat()
{
    return mBatVoltage;
}

// IN_LINE u16 Board_GetKbValue()
// {
//     return mAdcKbValue;
// }

IN_LINE bool Board_IsPlugIn()
{
    return mIsPlugIn;
}

void Board_SendDataDp(u8 *buff, u8 len)
{
    HalGpioFmuxConfig(TEST_DP_PIN, FMUX_UART0_TX);     // P10 设置为 TX
    HalUartSendBuf(UART0, buff, len);   // 同步发送
    HalGpioFmuxConfig(TEST_DP_PIN, FMUX_UART0_RX);     // P10 设置为 RX
}

void Board_SetVBusHigh()
{
    HalUartDeInit(UART1);
    VBUS_RX_PIN_AIN;
    mPlugCheckStep = 0;
    Board_SetVBusHzLevel(0); /*VBUS可输出低电平（受控于VBUS_TX）*/
    VBUS_TX_PIN_GPIO_OUT_H;
}

void Board_SetVBusLow()
{
    HalUartDeInit(UART1);
    VBUS_RX_PIN_AIN;
    mPlugCheckStep = 0;
    VBUS_TX_PIN_GPIO_OUT_L;
    Board_SetVBusHzLevel(0); /*VBUS可输出低电平（受控于VBUS_TX）*/
}

void Board_SendDataVBus(u8 *buff, u8 len)
{
    mPlugCheckStep = 0;
    Board_SetVBusHigh();    // 确保VBUS在发送数据之前是高电平防止UART外设报错
    Mcu_Delayms(10);
    Uart1_Init(3333);
    // HalUartBaudSet(UART1, 3333);
    // Mcu_Delayms(10);
    Board_SetVBusTX();
    HalUartSendBuf(UART1, buff, len);   // 同步发送
    HalUartBaudSet(UART1, 208);
    Board_SetVBusRx();
}

void Board_StartPlugCheck()   
{
    HalUartDeInit(UART1);
    VBUS_RX_PIN_AIN;
    Board_SetVBusHzLevel(0); /*VBUS可输出低电平（受控于VBUS_TX）*/
    VBUS_TX_PIN_GPIO_OUT_L;
    mPlugCheckStep = 1;
}

void Board_StartMeasuring()
{
    u16 load_res;   // mΩ
    while(mAdcDone == false);   // 等待上次转换完毕
    Board_AdcStartScan(ADC_CH_TEST_DN_MASK|ADC_CH_VBAT_MASK);
    while(mAdcDone == false);   // 等待上次转换完毕
    load_res = 1000 * 100 * mTestDnVoltage / (mBatVoltage - mTestDnVoltage);
    TW_EvMeasDone(load_res, 0XFFFF);    // 板子硬件不支持获取接入产品的电池电压
}

// 30ms 定时器
static void BoardTimer()
{
    if(mPlugCheckStep)
    {
        Board_SetVBusHzLevel(1);    // VBUS 高阻（外部有上拉）
        Board_AdcStartScan(ADC_CH_VBAT_MASK|ADC_CH_KB_MASK|ADC_CH_VBUS_MASK|ADC_CH_LIGHT_MASK);    // ADC开始运行一次，10ms内出结果，否则会重复启动转换
    }
    if(mNeedSleep)
    {
        if (Keyboard_GetLastStatus() == KEY_STATUS_RELEASE) // 按键松手后才真正休眠，避免休眠后马上又唤醒
        {
            Board_EnterSleep();
            mNeedSleep = false;
        }
    }

    BootTime+=3;
    if(BootTime == 201)  // 启动后需要等待2秒初始化组件
    {
        BM_Init();
    }

    if(Keyboard_GetLastKey() == KEY_OK && Keyboard_GetLastStatus() == KEY_STATUS_PRESS)
    {
        mResetTime+=3;
        if(mResetTime >= 1000)
        {
            NVIC_SystemReset();
        }
    }
    else
    {
        mResetTime = 0;
    }

    Wdt_Clear();
}

// 开始一次ADC扫描
// ch_mask： 要扫描的通道掩码，1表示使能，对应位代表的通道号见 AdcChannel_t 
static void Board_AdcStartScan(u8 ch_mask)
{
    AdcCfg_t cfg;
    mAdcConvertedCh = 0;
    mAdcMissData = false;
    mAdcDone = false;
    mAdcChMask = ch_mask;
    cfg.channel_flag = mAdcChMask;
    cfg.is_continue_mode = FALSE;
    cfg.is_high_resolution = ADC_CH_MODE_MASK;
    HalAdcInit();
    
    HalAdcChannelConfig(cfg, Adc_Event);
    HalAdcClockConfig(HAL_ADC_CLOCK_80K);
    // subWriteReg(0x4000F000 + 0x7c,3,3,0);   // 设置ADC转换时间：0: 1.56us, 1: 2.34us
    HalAdcStart();  // 开始转换
}

static void GpioInit()
{
    gpio_init_param_t ip[] = GPIO_INIT_LIST;
    for(u8 i = 0; i < sizeof(ip) / sizeof(gpio_init_param_t); i++)
        Gpio_PinInit(&ip[i]);
}

static void SPI0_Init()
{
#ifdef BOARD_USE_CUST_SPI_DRV
    Spi_Init();
    HalGpioFmuxConfig(SPI_MISO_PIN, FMUX_SPI_0_RX);
    HalGpioFmuxConfig(SPI_MOSI_PIN, FMUX_SPI_0_TX);
    HalGpioFmuxConfig(SPI_SCK_PIN, FMUX_SPI_0_SCK);
    HalGpioFmuxConfig(SPI_LCD_CS_PIN, FMUX_SPI_0_SSN);
#else
    spi_Cfg_t cfg;
    cfg.sclk_pin = SPI_SCK_PIN;
    cfg.ssn_pin = SPI_LCD_CS_PIN;
    cfg.MOSI = SPI_MOSI_PIN;
    cfg.MISO = SPI_MISO_PIN;
    cfg.baudrate = 100000;
    cfg.spi_tmod = SPI_TXD;
    cfg.spi_scmod = SPI_MODE0;
    cfg.spi_dfsmod = SPI_1BYTE;
    cfg.dma_rx_enable = false;
    cfg.dma_tx_enable = false;
    cfg.int_mode = false;   // true： 中断模式; false： 查询模式
    cfg.force_cs = false; // true： 选用软件 CS 控制 false： 选用硬件 CS 控制
    cfg.is_slave = false;
    cfg.evt_handler = NULL;
    HalSpiInit(SPI0);
    HalSpiMasterConfig(AP_SPI0, &cfg);
#endif
}


static void Uart0_Init()
{
    uart_Cfg_t cfg = {
  .tx_pin = GPIO_DUMMY,
  .rx_pin = TEST_DP_PIN,
  .baudrate = 3333,
  .use_fifo = TRUE,
  .hw_fwctrl = FALSE,
  .use_tx_buf = FALSE,
  .parity     = FALSE,
  .evt_handler = Uart0_Event,
  };
  HalUartInit(UART0, cfg);//uart init
}

static void Uart1_Init(u32 baud)
{
    uart_Cfg_t cfg = {
  .tx_pin = GPIO_DUMMY,
  .rx_pin = GPIO_DUMMY,
  .baudrate = baud,
  .use_fifo = FALSE,
  .hw_fwctrl = FALSE,
  .use_tx_buf = FALSE,
  .parity     = FALSE,
  .evt_handler = Uart1_Event,
  };
  HalUartInit(UART1, cfg);//uart init
}

// 16个AD值如果最大值与最小值偏差过大返回false。
bool AdcKbResultCheck(u16 *adv, u8 len)
{
    s16 min = 0X7FFF;
    s16 max = 0;

    for(u8 i = 0; i < len; i++)
    {
        if(min > adv[i])min = adv[i];
        if(max < adv[i])max = adv[i];
    }
    return (max - min < 100);
}

static void Adc_Event(AdcEvt_t* e)
{
    if((e->type == HAL_ADC_EVT_DATA) && (mAdcConvertedCh  != mAdcChMask))
    {
        mAdcConvertedCh |= (1 << e->ch);
        if(e->ch == ADC_CH_VBUS)
        {
            if(mPlugCheckStep)
            {
                u32 dv = HalAdcValueCal(e->ch,e->data, e->size, FALSE);
                mVoltageVBus = dv * (1888 + 10) / 1888;
                if(mIsPlugIn == false)  // 未接入
                {   
                    if((s16)mVoltageVBus - (s16)mVoltageVBusLast <= -50 && mVoltageVBus < 2300) // 电压突降
                    {
                        mIsPlugIn = true;   // 标记接入
                    }
                }
                else    // 已接入
                {
                    if((s16)mVoltageVBus - (s16)mVoltageVBusLast >= 50 && mVoltageVBus >= 2300) // 电压突增并且电压大于2.3V
                    {
                        mIsPlugIn = false;   // 标记拔掉
                    }
                }
                mVoltageVBusLast = mVoltageVBus;
            }
        }
        else if(e->ch == ADC_CH_VBAT)
        {
            mBatVoltage = HalAdcValueCal(e->ch, e->data, e->size, TRUE) * 11;
            for(int i = 0; i < 16; i++)
            {
                mRand <<= 2;
                mRand += e->data[i] & 0x0003;
            }
        }
        else if(e->ch == ADC_CH_KB)
        {
            if(AdcKbResultCheck(e->data, e->size)) // 数据有效
            {
                mAdcKbValue = HalAdcValueCal(e->ch, e->data, e->size, TRUE);
                KeyBoard_EvNewAdv(mAdcKbValue);
            }
            else    // 数据无效，需要重新转换
            {
                mAdcMissData = true;
            }
            
        }
        else if(e->ch == ADC_CH_LIGHT)
        {
            // mLight = MedianFilter16b9(e->data);
            mLight = HalAdcValueCal(e->ch, e->data, e->size, TRUE);
        }
        else if(e->ch == ADC_CH_TEST_DN)
        {
            mTestDnVoltage = HalAdcValueCal(e->ch, e->data, e->size, TRUE);
        }
        
        if(mAdcConvertedCh == mAdcChMask)  // 所有通道转换完毕
        {
            mAdcDone = true;
            if(mPlugCheckStep)
            {
                Board_SetVBusHzLevel(0);    // VBUS 输出低电平
            }
            // VBUS_TX_PIN_GPIO_OUT_L;
            // AIN_KB_PIN_GPIO_OUT_L;
            // AIN_KB_PIN_AIN;
        }
    }
}


static void Uart0_Event(uart_Evt_t *e)
{
    switch(e->type)
	{
		case UART_EVT_TYPE_RX_DATA:
		case UART_EVT_TYPE_RX_DATA_TO:
		{
			uint16_t i;
			for(i=0; i<e->len; i++) 
            {
				Link_EvReceivedByte(e->data[i],LINK_PORT_DP);
			}
		}
		break;
		
		case UART_EVT_TYPE_TX_COMPLETED:
		break;
        default: break;
	}
}

static void Uart1_Event(uart_Evt_t *e)
{
    switch(e->type)
	{
		case UART_EVT_TYPE_RX_DATA:
		case UART_EVT_TYPE_RX_DATA_TO:
		{
			uint16_t i;
			for(i=0; i<e->len; i++) 
            {
				Link_EvReceivedByte(e->data[i],LINK_PORT_VBUS);
			}
		}
		break;
		
		case UART_EVT_TYPE_TX_COMPLETED:
		break;
        default: break;
	}
}







